package com.ask.ff.upload_server.controller;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

@RestController
public class CkEditorUploadController {

    /**
     * 接收 CkEditor5 图像上传请求
     * @param file 上传的文件，记得 ckeditor5 上传的参数为 upload
     * @param moreUrls 是否生成多张图
     * @param api_key 密钥（请求头，必须为：ASK_D_FF），你可以自行更改
     * @param request 请求
     * @return 响应数据
     */
    @PostMapping("/upload")
    public Object upload(@RequestParam("upload") MultipartFile file, String moreUrls, @RequestHeader("Accept-Api-Key") String api_key, HttpServletRequest request) {
        // 响应数据
        HashMap<String, Object> responseData = new HashMap<>(); // 响应数据一层数据
        HashMap<String, String> responseDataInfo = new HashMap<>(); // 响应数据二层数据

        // 判断密钥是否准确（模拟）
        if (api_key == null || !api_key.equals("ASK_D_FF")) {
            responseDataInfo.put("message", "你还没有足够的权力上传图像，请先获取密钥！");
            responseData.put("error", responseDataInfo);
            return responseData;
        }

        // 判断是否上传的图像文件
        if (file.isEmpty()) {
            responseDataInfo.put("message", "未找到图片源！");
            responseData.put("error", responseDataInfo);
            return responseData;
        }

        // 上传到哪个磁盘文件夹下（是虚拟路径）
        String fileMkdirsPath = "E:" + File.separator + "ck-file" + File.separator + "image";
        // 上传到哪个磁盘文件夹下的虚拟路径地址（例如：http://127.0.0.1:18080/image/）
        String urlImageMkdir = request.getScheme() + "://" + request.getLocalAddr() + ":" + request.getServerPort() + "/image/";

        // 调用上传文件
        String saveFile = null;
        try {
            saveFile = saveFile(file, fileMkdirsPath);
        } catch (IOException e) {
            e.printStackTrace();
            responseDataInfo.put("message", "上传失败");
            responseData.put("error", responseDataInfo);
            return responseData;
        }

        // 是否需要生成多个图片
        if (moreUrls == null) {
            // 不需要，直接将上传后的图片在服务器中的地址返回给前端
            responseData.put("url", urlImageMkdir + saveFile); // 虚拟地址文件夹 + 文件名
            return responseData;
        }

        // 需要生成多个图像，我们这里准备生成三种尺寸，宽度为 30，120，360，高度等比例的
        String[] widthArr = {"60", "120"};
        try {
            responseDataInfo = imageScale(widthArr, fileMkdirsPath, saveFile, urlImageMkdir);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            responseDataInfo.put("message", "图像缩放生成失败，请稍后再试！");
            responseData.put("error", responseDataInfo);
            return responseData;
        }

        if (responseDataInfo.isEmpty()) {
            responseDataInfo.put("message", "图像缩放生成失败，请稍后尝试！");
            responseData.put("error", responseDataInfo);
            return responseData;
        }

        responseDataInfo.put("default", urlImageMkdir + saveFile);
        responseData.put("urls", responseDataInfo);
        return responseData;

    }

    /**
     * 保存文件
     *
     * @param file           上传的文件
     * @param fileMkdirsPath 上传到哪个文件夹下方
     * @return 上传后的文件新名字（只是文件名）
     * @throws IOException 上传异常
     */
    private String saveFile(MultipartFile file, String fileMkdirsPath) throws IOException {

        // 获取上传的文件名
        String originalFilename = file.getOriginalFilename();
        // 文件名为 null 终止程序
        assert originalFilename != null;
        // 获取上传文件的后缀名
        String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); //获取上传文件原来的名称
        // 上传后更改后的文件名
        String fileName = System.currentTimeMillis() + extension;

        // 文件夹不存在则创建该文件夹
        File temp = new File(fileMkdirsPath);
        if (!temp.exists()) temp.mkdirs();

        // 最终上传的文件
        File localFile = new File(fileMkdirsPath + File.separator + fileName);
        // 把上传的文件保存至本地
        file.transferTo(localFile);

        return fileName;
    }

    /**
     * 生成多图像
     *
     * @param widthArr      多图像的宽度数组
     * @param image_mkdir   源图像所在文件夹
     * @param imageName     源图像文件名
     * @param urlImageMkdir 上传后的虚拟文件夹地址
     * @return
     * @throws IOException
     */
    public HashMap<String, String> imageScale(String[] widthArr, String image_mkdir, String imageName, String urlImageMkdir) throws IOException, InterruptedException {
        HashMap<String, String> imageUrls = new HashMap<>();

        // 操作系统进程：（用来执行 ffmpeg 服务指令）当然要提前在电脑上安装好，配置好环境变量
        ProcessBuilder pb;
        // 依次生成缩放图片
        for (String width : widthArr) {
            // 生成新的文件名称：时间戳 + 文件后缀名
            String vf_image_name = System.currentTimeMillis() + imageName.substring(imageName.lastIndexOf("."));
            // 执行 FFMPEG 服务指令：对图像进行缩放
            pb = new ProcessBuilder(
                    "ffmpeg",
                    "-i",
                    image_mkdir + File.separator + imageName, // 源文件地址（路径+文件名）
                    "-vf",
                    "scale=" + width + ":-1", // 缩放 = 宽度：-1（高度等比例）
                    image_mkdir + File.separator + vf_image_name // 生成后的图像（路径+文件名）
            );
            pb.redirectErrorStream(true); // 将启动的进程的任何错误输出都将与标准输出流合并。
            pb.start().waitFor(); // 启动 …… 等待上方指令完成
            imageUrls.put(width, urlImageMkdir + vf_image_name); // 封装生成的图像信息，比如 {"120": "http://127.0.0.1:18080/2323267131.jpg"}
        }
        return imageUrls;
    }
}
